package com.qire.common.utils;

import android.app.Application;
import android.os.Parcelable;

import com.google.gson.Gson;
import com.google.gson.JsonSyntaxException;
import com.qire.common.basic.ObjectUtil;
import com.qire.common.basic.StringUtil;
import com.tencent.mmkv.MMKV;

import java.lang.reflect.Type;
import java.util.Collections;
import java.util.Set;

/**
 * 缓存存储工具，基于MMKV
 */
public class CacheStorageUtil {

    private CacheStorageUtil() {
        throw new UnsupportedOperationException("不能初始化这个工具");
    }

    /**
     * 初始化，默认会在路径 $(FilesDir)/mmkv/ 上开辟一个存储空间
     * @param  application Application
     */
    public static void init(Application application) {
        // 指定一个自己的目录
//        String dir = getFilesDir().getAbsolutePath() + "/mmkv_2";
//        String rootDir = MMKV.initialize(dir);

        // 使用默认
        String rootDir = MMKV.initialize(application);
        Logger.i("MMKV root: " + rootDir);
    }

    /**
     * 导入 SharedPreferences 兼容数据
     */
    private static void importSharedPreferences() {
//        //SharedPreferences preferences = getSharedPreferences("myData", MODE_PRIVATE);
//        MMKV preferences = MMKV.mmkvWithID("myData");
//        // 迁移旧数据
//        {
//            SharedPreferences old_man = getSharedPreferences("myData", MODE_PRIVATE);
//            preferences.importFromSharedPreferences(old_man);
//            old_man.edit().clear().commit();
//        }
//        // 跟以前用法一样
//        SharedPreferences.Editor editor = preferences.edit();
//        editor.putBoolean("bool", true);
//        editor.putInt("int", Integer.MIN_VALUE);
//        editor.putLong("long", Long.MAX_VALUE);
//        editor.putFloat("float", -3.14f);
//        editor.putString("string", "hello, imported");
//        HashSet<String> set = new HashSet<String>();
//        set.add("W"); set.add("e"); set.add("C"); set.add("h"); set.add("a"); set.add("t");
//        editor.putStringSet("string-set", set);
//        // 无需调用 commit()
//        //editor.commit();
    }

    private static MMKV query(String storageId) {
        return MMKV.mmkvWithID(storageId);
    }

    /**
     * 默认缓存实例封装，利用static 延时加载机制，是的DEF单例会在使用时被夹在，避免 MMKV.defaultMMKV() 在 MMKV.initialize(application) 前调用；
     */
    private static class CacheStorage {
        private static final MMKV DEF = MMKV.defaultMMKV();
    }

    /**
     * 保存数据的方法，我们需要拿到保存数据的具体类型，然后根据类型调用不同的保存方法
     *
     * @param key
     * @param object
     */
    public static void save(String key, Object object) {
        if (object instanceof String) {
            CacheStorage.DEF.encode(key, (String) object);
        } else if (object instanceof Integer) {
            CacheStorage.DEF.encode(key, (Integer) object);
        } else if (object instanceof Boolean) {
            CacheStorage.DEF.encode(key, (Boolean) object);
        } else if (object instanceof Float) {
            CacheStorage.DEF.encode(key, (Float) object);
        } else if (object instanceof Long) {
            CacheStorage.DEF.encode(key, (Long) object);
        } else if (object instanceof Double) {
            CacheStorage.DEF.encode(key, (Double) object);
        } else if (object instanceof byte[] ) {
            CacheStorage.DEF.encode(key, (byte[]) object);
        } else {
//            CacheStorage.DEF.encode(key, object.toString());
            CacheStorage.DEF.encode(key, new Gson().toJson(object));
        }
    }

    public static void saveSet(String key, Set<String> sets) {
        CacheStorage.DEF.encode(key, sets);
    }

    public static void saveParcelable(String key, Parcelable obj) {
        CacheStorage.DEF.encode(key, obj);
    }

    /**
     * 如果缓存 key 的数据与 data 相同则不保存，否则保存
     * @param key 缓存KEY
     * @param data 缓存数据
     * @return 如果缓存 key 的数据与 data 相同返回 false，否则 true
     */
    public static boolean saveIfNotExist(String key, Object data) {
        Object cacheData;

        if (data instanceof Integer) {
            cacheData = queryInt(key);
        } else if (data instanceof Double) {
            cacheData = queryDouble(key);
        } else if (data instanceof Long) {
            cacheData = queryLong(key);
        } else if (data instanceof Boolean) {
            cacheData = queryBoolean(key);
        } else if (data instanceof Float) {
            cacheData = queryFloat(key);
        } else if (data instanceof byte[]) {
            cacheData = queryBytes(key);
        } else if (data instanceof String) {
            cacheData = queryString(key);
        } else {
            cacheData = query(key, data.getClass());
        }

        if(ObjectUtil.equals(cacheData, data)) {
            return false;
        }

        save(key, data);
        return true;
    }

    /**
     * 得到保存数据的方法，我们根据默认值得到保存的数据的具体类型，然后调用相对于的方法获取值
     */
    public static Integer queryInt(String key) {
        return queryInt(key, 0);
    }
    public static Integer queryInt(String key, int defaultValue) {
        return CacheStorage.DEF.decodeInt(key, defaultValue);
    }
    public static Double queryDouble(String key) {
        return queryDouble(key, 0.00);
    }
    public static Double queryDouble(String key, double defaultValue) {
        return CacheStorage.DEF.decodeDouble(key, defaultValue);
    }
    public static Long queryLong(String key) {
        return queryLong(key, 0L);
    }
    public static Long queryLong(String key, long defaultValue) {
        return CacheStorage.DEF.decodeLong(key, defaultValue);
    }
    public static Boolean queryBoolean(String key) {
        return queryBoolean(key, false);
    }
    public static Boolean queryBoolean(String key, boolean defaultValue) {
        return CacheStorage.DEF.decodeBool(key, defaultValue);
    }
    public static Float queryFloat(String key) {
        return queryFloat(key, 0F);
    }
    public static Float queryFloat(String key, float defaultValue) {
        return CacheStorage.DEF.decodeFloat(key, defaultValue);
    }
    public static byte[] queryBytes(String key) {
        return CacheStorage.DEF.decodeBytes(key);
    }
    public static String queryString(String key) {
        return queryString(key, "");
    }
    public static String queryString(String key, String defaultValue) {
        return CacheStorage.DEF.decodeString(key,defaultValue);
    }
    public static Set<String> queryStringSet(String key) {
        return queryStringSet(key, Collections.<String>emptySet());
    }
    public static Set<String> queryStringSet(String key, Set<String> defaultValue) {
        return CacheStorage.DEF.decodeStringSet(key, defaultValue);
    }
    public static <T extends Parcelable> T  queryParcelable(String key) {
        return queryParcelable(key, null);
    }
    public static <T extends Parcelable> T  queryParcelable(String key, Class<T> defaultValue) {
        return CacheStorage.DEF.decodeParcelable(key, defaultValue);
    }
    public static <T> T query(String key, Type type) {
        String json = queryString(key);
        if(StringUtil.isEmpty(json))
            return null;
        T data = null;
        try {
            data = new Gson().fromJson(json, type);
        } catch (JsonSyntaxException e) {
            // 解析异常，可能是数据类型以发生改变，也可能是数据格式错误。可能由于版本更换后选择了其他类型，固再次直接清除老旧数据，如果有其他需求，可以再做处理
            save(key, null);
            e.printStackTrace();
        }
        return data;
    }

    /**
     * 移除某个key对
     *
     * @param key
     */
    public static void removeKey(String key) {
        CacheStorage.DEF.removeValueForKey(key);
    }

    /**
     * 清除所有key
     */
    public static void clearAll() {
        CacheStorage.DEF.clearAll();
    }

}
